//== SAGITTARIUS ============================================================================

//== BEGINNING OF CODE ===============================================================

#include "sagittarius/core/SagittariusCore.h"
#include SAGITTARIUS_GREYLIST_IMPLH
#include "sagittarius/io/io.h"
#include <malloc.h>
#include <stddef.h>
//#include <string.h>

void greylist_grow(greylist_t* gl) {
    //must hold lock before calling this fun
    uint32 n;
    sg_glr *r, *u, *v;
    AN(0);
    
    n = 16*gl->n;
    
    r = malloc(n*sizeof(sg_glr));
    //need to setup indirection tables
    u = gl->head;
    v = r;
    for(; u!=gl->tail; ++u, ++v) {
        if(u == gl->r + gl->n)
            u = gl->r;
        *v = *u;
    }
    free(gl->r);
    gl->r = r;
}

void init_greylist(greylist_t* gl) {
    size_t i;
    INITSEMA(gl->sema);
    WLSEMA(gl->sema);
    
    gl->n = 16*4096;
    gl->r = malloc(gl->n*sizeof(sg_glr));
    gl->head = gl->tail = gl->r;
    
    for(i=0; i<gl->n; ++i) {
        
    }
    
    WUSEMA(gl->sema);
}

void greylist_push(greylist_t* gl, void* p) {
    AT(p != NULL, "Cannot push a null pointer onto greylist");
    WLSEMA(gl->sema);
    
    if(gl->tail->v) {
        //list full
        greylist_grow(gl);
    }
    AZ(gl->tail); //make sure tail is available
    gl->tail->v = p;
    ++gl->tail;
    if(gl->tail == gl->r+gl->n)
        gl->tail = gl->r; //wrap around
    
    WUSEMA(gl->sema);
}

void* greylist_pop(greylist_t* gl) {
    void* v;
    WLSEMA(gl->sema);
    
    //if(!gl->head->v) {
        //WUSEMA(gl->sema);
        //return NULL; //empty
    //}
    
    v = gl->head->v;
    gl->head->v = NULL; //makes the node available
    if(gl->head != gl->tail) //don't let head get "ahead" of tail
        ++gl->head;
    
    WUSEMA(gl->sema);
    
    return v;
}

void dump_greylist(int fd, greylist_t* gl) {
    sg_glr* p;
    SG_WRITE(fd, "Grey list\n");
    SG_WRITE(fd, "  Head: ");
    sg_writePtr(fd, gl->head);
    SG_WRITE(fd, "\n  Tail: ");
    sg_writePtr(fd, gl->tail);
    SG_WRITE(fd, "\n");
    for(p = gl->head; p!=gl->tail;) {
        SG_WRITE(fd, "\n    Record ");
        sg_writePtr(fd, p);
        SG_WRITE(fd, ":\n");
        SG_WRITE(fd, "\n      ");
        sg_writePtr(fd, p->v);
        ++p;
        if(p == gl->r + gl->n)
            p = gl->r;
    }
}
